#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>

// 定义线程数量
#define NUM_READERS 3
#define NUM_WRITERS 2

// 操作次数配置
#define MAX_OPERATIONS 12

// 共享资源
int shared_resource = 0;

// 信号量定义
sem_t mutex;         // 互斥访问共享变量
sem_t resource;      // 控制资源访问
sem_t writer_prio;   // 写者优先信号量

// 状态变量
int reader_count = 0;       // 当前读者数量
int writer_count = 0;       // 当前写者数量
int writer_waiting = 0;     // 等待的写者数量
int writer_delay_count = 0; // 写者被延迟的次数
int writer_priority = 0;    // 写者是否优先

// 统计数据
struct timeval global_start;   // 全局开始时间
long reader_wait_time[NUM_READERS] = {0};  // 读者等待时间
long writer_wait_time[NUM_WRITERS] = {0};  // 写者等待时间
int reader_wait_count[NUM_READERS] = {0};  // 读者等待次数
int writer_wait_count[NUM_WRITERS] = {0};  // 写者等待次数

// 操作序列
struct Operation {
    int time;           // 操作时间点
    int thread_id;      // 线程ID
    char type;          // 'R'表示读者，'W'表示写者
    int duration;       // 操作持续时间
};

// 定义操作序列
struct Operation operations[MAX_OPERATIONS] = {
    {0, 0, 'W', 100},     // Writer1 到达，需写入100
    {100, 0, 'R', 400},   // Reader1 到达，需读取400
    {200, 1, 'R', 100},   // Reader2 到达，需读取100
    {300, 1, 'W', 100},   // Writer2 到达，需写入100
    {400, 0, 'W', 200},   // Writer1 需写入200
    {500, 2, 'R', 400},   // Reader3 到达，需读取400
    {600, 1, 'R', 300},   // Reader2 需读取300
    {700, 1, 'W', 200},   // Writer2 需写入200
    {800, 0, 'W', 200},   // Writer1 需写入200
    {900, 0, 'R', 300},   // Reader1 需读取300
    {1000, 2, 'R', 400},  // Reader3 需读取400
    {1100, 0, 'W', 200}   // Writer1 需写入200
};

// 获取当前时间（毫秒）
long current_time_ms() {
    struct timeval now;
    gettimeofday(&now, NULL);
    return (now.tv_sec - global_start.tv_sec) * 1000 + 
           (now.tv_usec - global_start.tv_usec) / 1000;
}

// 读者线程函数
void* reader(void* arg) {
    int id = *((int*)arg);
    
    for (int i = 0; i < MAX_OPERATIONS; i++) {
        if (operations[i].type == 'R' && operations[i].thread_id == id) {
            // 等待到达指定时间
            while (current_time_ms() < operations[i].time) {
                usleep(1000); // 睡眠1毫秒
            }
            
            struct timeval start, end;
            gettimeofday(&start, NULL);
            
            printf("时间 %ld: Reader %d 请求读取资源\n", current_time_ms(), id + 1);
            
            // 请求访问
            sem_wait(&mutex);
            
            // 公平策略：如果写者被延迟3次以上且有写者等待，读者应该等待
            if (writer_priority && writer_waiting > 0) {
                sem_post(&mutex);
                
                printf("时间 %ld: Reader %d 让步给写者\n", current_time_ms(), id + 1);
                sem_wait(&writer_prio);
                sem_wait(&mutex);
            }
            
            reader_count++;
            if (reader_count == 1) { // 第一个读者需要获取资源锁
                sem_wait(&resource);
            }
            sem_post(&mutex);
            
            // 计算等待时间
            gettimeofday(&end, NULL);
            long wait_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
            reader_wait_time[id] += wait_time;
            reader_wait_count[id]++;
            
            // 开始读取
            printf("时间 %ld: Reader %d 开始读取 (值=%d)\n", current_time_ms(), id + 1, shared_resource);
            usleep(operations[i].duration * 1000); // 模拟读取时间
            printf("时间 %ld: Reader %d 完成读取\n", current_time_ms(), id + 1);
            
            // 读取完成
            sem_wait(&mutex);
            reader_count--;
            if (reader_count == 0) { // 最后一个读者释放资源锁
                sem_post(&resource);
                
                // 如果有写者等待且写者优先，唤醒所有写者
                if (writer_waiting > 0 && writer_priority) {
                    printf("时间 %ld: 最后一个读者离开，允许写者访问\n", current_time_ms());
                }
            }
            sem_post(&mutex);
        }
    }
    
    return NULL;
}

// 写者线程函数
void* writer(void* arg) {
    int id = *((int*)arg);
    
    for (int i = 0; i < MAX_OPERATIONS; i++) {
        if (operations[i].type == 'W' && operations[i].thread_id == id) {
            // 等待到达指定时间
            while (current_time_ms() < operations[i].time) {
                usleep(1000); // 睡眠1毫秒
            }
            
            struct timeval start, end;
            gettimeofday(&start, NULL);
            
            printf("时间 %ld: Writer %d 请求写入资源\n", current_time_ms(), id + 1);
            
            // 请求访问
            sem_wait(&mutex);
            writer_waiting++;
            sem_post(&mutex);
            
            // 获取资源独占权
            sem_wait(&resource);
            
            sem_wait(&mutex);
            writer_waiting--;
            writer_count++;
            
            // 公平策略：连续3次被延迟后启用写者优先
            if (writer_delay_count >= 3 && !writer_priority) {
                printf("时间 %ld: 写者被延迟3次，启用写者优先模式\n", current_time_ms());
                writer_priority = 1;
            }
            sem_post(&mutex);
            
            // 计算等待时间
            gettimeofday(&end, NULL);
            long wait_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
            writer_wait_time[id] += wait_time;
            writer_wait_count[id]++;
            
            // 开始写入
            printf("时间 %ld: Writer %d 开始写入\n", current_time_ms(), id + 1);
            shared_resource++; // 修改共享资源
            usleep(operations[i].duration * 1000); // 模拟写入时间
            printf("时间 %ld: Writer %d 完成写入 (新值=%d)\n", current_time_ms(), id + 1, shared_resource);
            
            // 写入完成
            sem_wait(&mutex);
            writer_count--;
            writer_delay_count = 0; // 重置延迟计数
            
            if (writer_waiting == 0 && writer_priority) {
                // 没有写者等待时，如果启用了写者优先，关闭它
                printf("时间 %ld: 没有写者等待，关闭写者优先模式\n", current_time_ms());
                writer_priority = 0;
                
                // 释放所有等待的读者
                for (int j = 0; j < reader_count; j++) {
                    sem_post(&writer_prio);
                }
            }
            sem_post(&mutex);
            
            sem_post(&resource);
        }
    }
    
    return NULL;
}

int main() {
    // 初始化信号量
    sem_init(&mutex, 0, 1);
    sem_init(&resource, 0, 1);
    sem_init(&writer_prio, 0, 0);
    
    // 记录开始时间
    gettimeofday(&global_start, NULL);
    
    // 创建读者线程
    pthread_t readers[NUM_READERS];
    int reader_ids[NUM_READERS];
    for (int i = 0; i < NUM_READERS; i++) {
        reader_ids[i] = i;
        pthread_create(&readers[i], NULL, reader, &reader_ids[i]);
    }
    
    // 创建写者线程
    pthread_t writers[NUM_WRITERS];
    int writer_ids[NUM_WRITERS];
    for (int i = 0; i < NUM_WRITERS; i++) {
        writer_ids[i] = i;
        pthread_create(&writers[i], NULL, writer, &writer_ids[i]);
    }
    
    // 等待所有线程完成
    for (int i = 0; i < NUM_READERS; i++) {
        pthread_join(readers[i], NULL);
    }
    for (int i = 0; i < NUM_WRITERS; i++) {
        pthread_join(writers[i], NULL);
    }
    
    // 计算平均等待时间
    printf("\n=== 读者等待时间统计 ===\n");
    double total_reader_wait = 0;
    int total_reader_ops = 0;
    for (int i = 0; i < NUM_READERS; i++) {
        if (reader_wait_count[i] > 0) {
            double avg = reader_wait_time[i] / (double)reader_wait_count[i] / 1000.0;
            printf("Reader %d 平均等待时间: %.2f ms\n", i + 1, avg);
            total_reader_wait += reader_wait_time[i];
            total_reader_ops += reader_wait_count[i];
        }
    }
    if (total_reader_ops > 0) {
        printf("所有读者平均等待时间: %.2f ms\n", total_reader_wait / total_reader_ops / 1000.0);
    }
    
    printf("\n=== 写者等待时间统计 ===\n");
    double total_writer_wait = 0;
    int total_writer_ops = 0;
    for (int i = 0; i < NUM_WRITERS; i++) {
        if (writer_wait_count[i] > 0) {
            double avg = writer_wait_time[i] / (double)writer_wait_count[i] / 1000.0;
            printf("Writer %d 平均等待时间: %.2f ms\n", i + 1, avg);
            total_writer_wait += writer_wait_time[i];
            total_writer_ops += writer_wait_count[i];
        }
    }
    if (total_writer_ops > 0) {
        printf("所有写者平均等待时间: %.2f ms\n", total_writer_wait / total_writer_ops / 1000.0);
    }
    
    // 销毁信号量
    sem_destroy(&mutex);
    sem_destroy(&resource);
    sem_destroy(&writer_prio);
    
    return 0;
}